# 4.读取Loader ​ 由于MBR的大小是固定的,只有512字节。而且MBR的前446个字节是主引导加载程序,接下来的64个字节包含了4个分区的记录,最后两个字节的内容固定为0xAA55作为有效MBR的标识。所以很有必要使用MBR做为中转,加载另外一个内核加载程序。由于这个内核加载程序是我们自己写的,所以它的大小可以任意(而MBR固定为512字节),下面加载内核加载程序(Loader)到0x900处。 ```nasm ;内核加载程序--LBA28 ;下面读取硬盘扇区LBA28--------------------------------------- mov dx,0x1f1 mov al,0 ;al=0 out dx,al inc dx ;0x1f2 mov al,0x1 ;读取一个扇区--------------------------- out dx,al inc dx ;0x1f3 mov al,0x1 out dx,al inc dx ;0x1f4 mov al,0 out dx,al inc dx ;0x1f5 out dx,al inc dx ;0x1f6 mov al,1110_0000b ;lba主盘 out dx,al inc dx ;0x1f7 mov al,0x20 ;读命令 out dx,al .wait: ;等待硬盘准备完成 in al,dx and al,0x88 cmp al,0x08 jnz .wait mov cx,256 ;256=要读取的扇区数x256---------------------------- mov dx,0x1f0 mov bx,LOADER_BASE ;bx=LOADER_BASE .read: in ax,dx mov [bx],ax ;将ax中的值读入[bx] add bx,2 loop .read ;-----------------硬盘读取完成 ``` ​ 由于该程序仅被使用一次,所以没必要将其抽象为通用函数,必要的时候直接进行更改即可。 ​ 该程序将会把位于1号扇区的数据读入到0x900处。 ## 1.完整的MBR程序 ```nasm ;MBR程序,用于加载loader LOADER_BASE equ 0x900 org 0x7c00 MBR_start: ;现在es,cs,ss,ds,fs,gs ;r8,r9,r10,r11,r12,,r13,r14,r15,rbx,rbp均为0 mov ds,bx mov sp,0x7c00 ;设定栈为ss:sp=0:0x7c00 .clean_screen: ;清除屏幕 mov ax,0x0600 mov bx,0x0700 mov cx,0 mov dx,0x184f int 10h .set_cursor: ;设置光标 mov ah,0x02 mov bh,0x00 ;页号 mov dx,0x0000 ;(DH,DL) int 10h .display_str: ;显示:“MBR loader successfully!" mov ax,0x1301 ;光标随字符走 mov bp,Message ;字符地址:es:bp=0:Message mov cx,24 ;字符串长度 mov dx,0 ;字符打印位置 mov bl,0011b ;字符串属性:前景青色,背景黑色(设置颜色时注意!!!) int 0x10 ;下面读取硬盘扇区LBA28--------------------------------------- mov dx,0x1f1 mov al,0 ;al=0 out dx,al inc dx ;0x1f2 mov al,0x1 ;读取一个扇区--------------------------- out dx,al inc dx ;0x1f3 mov al,0x1 out dx,al inc dx ;0x1f4 mov al,0 out dx,al inc dx ;0x1f5 out dx,al inc dx ;0x1f6 mov al,1110_0000b ;lba主盘 out dx,al inc dx ;0x1f7 mov al,0x20 ;读命令 out dx,al .wait: ;等待硬盘准备完成 in al,dx and al,0x88 cmp al,0x08 jnz .wait mov cx,256 ;256=要读取的扇区数x256---------------------------- mov dx,0x1f0 mov bx,LOADER_BASE ;bx=LOADER_BASE .read: in ax,dx mov [bx],ax ;将ax中的值读入[bx] add bx,2 loop .read ;-----------------硬盘读取完成 jmp LOADER_BASE Message: db "MBR loader successfully!" times 510-($-$$) db 0 dw 0xaa55 ``` ​ 在加载完loader后,直接`jmp LOADER_BASE`,进入loader即可 loader现在很简单,如下: ```nasm org 0x900 hlt ;休眠CPU ``` ## 2.修改Makefile ​ 1.修改`meOS/Kernel/init/makefile`如下: ```makefile %.bin:%.asm nasm $*.asm -o $*.bin mbr:mbr.bin loader:loader.bin ``` 实际上就添加了第四行 ​ 2.修改`meOS/makefile`如下: ```makefile start: make mbr make loader make bochs .PHONY:start mbr clean bochs: cd image&&bochsdbg -q -f bochsrc.bxrc mbr: cd Kernel/init&&make mbr dd if=Kernel/init/mbr.bin of=image/c.img bs=512 count=1 @echo "----------------MBR----------------------------" loader: cd Kernel/init&&make loader dd if=Kernel/init/loader.bin of=image/c.img bs=512 count=1 seek=1 @echo "----------------LOADER-------------------------" clean: -@cd image&&erase /F /Q *.lock -@cd Kernel/init&&erase /F /Q *.bin ``` 实际上添加了3、14、15、16行 ## 运行结果 运行`start.cmd`输入`make`运行Bochs。 调试输出如下: > Next at t=0 > (0) [0x0000fffffff0] f000:fff0 (unk. ctxt): jmpf 0xf000:e05b ; ea5be000f0 > **\ b 0x900** > **\ u/5 0x900** > `00000900: ( ): add byte ptr ds:[bx+si], al ; 0000` > 00000902: ( ): add byte ptr ds:[bx+si], al ; 0000 > 00000904: ( ): add byte ptr ds:[bx+si], al ; 0000 > 00000906: ( ): add byte ptr ds:[bx+si], al ; 0000 > 00000908: ( ): add byte ptr ds:[bx+si], al ; 0000 > **\ c** > (0) Breakpoint 1, 0x0000000000000900 in ?? () > Next at t=6122367 > (0) [0x000000000900] 0000:0900 (unk. ctxt): hlt ; f4 > **\ u/5 0x900** > `00000900: ( ): hlt ; f4` > 00000901: ( ): add byte ptr ds:[bx+si-6002], bh ; 00b88ee8 > 00000905: ( ): mov byte ptr gs:0x0010, 0x61 ; 65c606100061 > 0000090b: ( ): hlt ; f4 > 0000090c: ( ): add byte ptr ds:[bx+si], al ; 0000 > **\ q** > (0).\[6122367][0x000000000900] 0000:0900 (unk. ctxt): hlt ; f4 可以看到,刚开始0x900处的数据为0000,而在执行`jmp LOADER_BASE`后,也就是Loader被读取完后,0x900处的数据变成了`0xf4`也就是`hlt`,这与loader源代码内容相同,说明loader被成功读取。